#include "../common/common.h"
#include "ImageGradient.h"
/*
  计算出一个移动窗口的所有的block的位置及一个block中所有像素对不同cell的权重。
  后面通过给力移动窗口的point的就可以参考这个表的权值进行计算了。
 */

#if !(defined _HOGCACHE_HEAD)
#define _HOGCACHE_HEAD
// HOG 存储结构：每个window包含105个block，每个block包含36 bins。
// window 64 * 128 block 16 * 16 cell 8 * 8 默认。
namespace HOG
{
  class HOGCache
  {
  public:
    enum {L2Hys=0};
    HOGCache(CvSize _winSize = cvSize(32,16), CvSize _blockSize = cvSize(16,16), CvSize _blockStride = cvSize(8,8), CvSize _cellSize = cvSize(8,8), double _sigma = -1.f, int _histogramNormType = L2Hys, double _L2HysThreshold=0.2 ) ;
    ~HOGCache();
    void normalizeBlockHistogram(float* _hist) const ;
    const float * GetBlock(cv::Point pt, float* buf) ;
    void GetWindow(cv::Point pt, float* buf) ;
    void calculateGradient(IplImage*img) ;
    void preprocessLocation(std::vector<cv::Point> &_winLocations) ;
    int compute(IplImage* img, std::vector<float>& HOGfeature, std::vector<cv::Point>& locations) ;
  private:
    // 私有的一些函数
    void init() ;
    float getWinSigma() ;
  private:
    // 私有的数据结构
    struct BlockData
    {
    BlockData():histOfs(0),imgOffset(){}
      int histOfs; // 每个block含有36bins，在内存中是连续存储的。histOfs用来指示连续存储的位置。
      cv::Point imgOffset; // imgOffset用来表示block在窗口中的window中的位置，左上角像素与window左上角像素的相对偏移。
    };
    // 每个PixData描述了一个Pix在进行HOG计算的时候所需要的信息。
    // gradOfs：该pix在grad的位置，(grad.cols*i+j)*2，2 表示的是grad是一个两通道的矩阵。
    // qangleOfs：该pix在qangle中的位置，(qangle.cols*i+j)*2，qangle为计算出的该像素的梯度角度所属的两个区间。
    // histOfs[4]:该像素点对4个cell的中hist直方图的贡献权重
    struct PixData
    {
      cv::Point location ; // 该像素的坐标点
      int histOfs[4] ;
      float histWeights[4] ;
      float gradWeight ; // 为幅值与高斯权重的乘积
    };
    std::vector<BlockData> blockData ;
    std::vector<PixData> pixData ;
    CvSize winSize, blockSize, cellSize ; // 移动窗口的大小, block的大小， cell的大小
    CvSize blockStride ; // block 一次便宜的大小
    CvSize nblocks, ncells ; // 一个移动窗口中横向，纵向中存在多少个blocks，一个blocks中横向，纵向中存在多少个cells。
    int blockHistogramSize ; // 一个block中HOG特征向量的维数
    int count1, count2 ,count4 ;
    cv::Mat grad, qangle ; // 用来存储梯度与角度的两个矩阵
    ImageGradient * imageGradient ; // 用来计算得到梯度与角度的class指针
    float winSigma ; // 高斯权重的标准差
    int histogramNormType ; 
    double L2HysThreshold ;
  };
}
#endif
